/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.servermanager;

import com.inspur.edp.i18n.resource.api.II18nResourceRTManager;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.I18nResource;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4RefDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataCustomizationFilter;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.api.entity.MetadataRTFilter;
import com.inspur.edp.lcm.metadata.api.entity.ServiceUnitInfo;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.cache.MetadataCacheManager;
import com.inspur.edp.lcm.metadata.cache.MetadataDistCacheManager;
import com.inspur.edp.lcm.metadata.cache.MetadataRtDistCache;
import com.inspur.edp.lcm.metadata.cache.RtCacheHandler;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.MetadataSerializer;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.configuration.I18nManagerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataSerializerHelper;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.serverapi.MetadataRTServerService;
import com.inspur.edp.lcm.metadata.servermanager.persistent.RepositoryFactory;
import com.inspur.edp.lcm.metadata.servermanager.util.MetadataServerManagerUitls;
import com.inspur.edp.lcm.metadata.servermanager.util.MetadataUtils;
import com.inspur.edp.lcm.metadata.spi.MetadataI18nService;
import io.iec.edp.caf.common.environment.EnvironmentUtil;
import io.iec.edp.caf.commons.layeringcache.cache.Cache;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import javax.annotation.PostConstruct;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zhaoleitr
 */
public class MetadataRTServerServiceImpl implements MetadataRTServerService {
    private static final Logger log = LoggerFactory.getLogger(MetadataRTServerServiceImpl.class);

    FileService fileService = new FileServiceImp();

    private II18nResourceRTManager i18nResourceRtManager;

    private II18nResourceRTManager getI18nResourceRtManager() {
        if (i18nResourceRtManager == null) {
            i18nResourceRtManager = SpringBeanUtils.getBean(II18nResourceRTManager.class);
        }
        return i18nResourceRtManager;
    }

    private final Lock lock = new ReentrantLock();
    private static String serverBasePath = "";
    private static String metadataAppPath = "";
    private static String metadataPlatformPath = "";
    private final MetadataServerManagerUitls utils = new MetadataServerManagerUitls();

    /**
     * 启动时加载所有元数据
     */
    @PostConstruct
    private void init() {
        log.info("Loading Metadata...");
        try {
            ExecutorService executor = Executors.newCachedThreadPool();
            executor.submit(
                this::loadAllMetadata);
        } catch (Exception e) {
            log.error("Loading Metadata Failed", e);
        }
    }

    @Override
    public MetadataDto getMetadataDtoRTByID(String id) {
        GspMetadata metadata = getMetadataRTByID(id);
        return MetadataDtoConverter.asDto(metadata);
    }

    private GspMetadata getMetadataRTByID(String metadataID) {
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataID, "");
        GspMetadata metadataCache = (GspMetadata) MetadataCacheManager.getMetadataInfo(metadataKey);
        if (metadataCache != null) {
            return metadataCache;
        }
        String metadataPackagePath = (String) MetadataCacheManager.getMetadataPathMapping(metadataKey);
        if (metadataPackagePath == null || metadataPackagePath.isEmpty()) {
//            throw new IllegalArgumentException("Could not find metadata, metadataid is " + metadataID);
            return null;
        }
        GspMetadata metadata = getMetadataByIdAndMetadataPath(metadataID, metadataPackagePath);
        RtCacheHandler.updateMetadataCache(metadataKey, metadata);
        return metadata;
    }

    public GspMetadata getMetadataByIdAndMetadataPath(String metadataId, String metadataPath) {
        String entryName = metadataPath.substring(metadataPath.indexOf(MetadataUtils.getMetadataPackageExtension()) + MetadataUtils.getMetadataPackageExtension().length() + 1);
        metadataPath = metadataPath.substring(0, metadataPath.indexOf(entryName) - 1);
        GspMetadata metadata = null;
        lock.lock();
        try {
            String manifestStr = "";
            StringBuilder sb = new StringBuilder();
            File file = new File(metadataPath);
            ZipFile zf = new ZipFile(file);
            InputStream in = new BufferedInputStream(new FileInputStream(metadataPath));
            Charset utf8 = StandardCharsets.UTF_8;
            ZipInputStream zipInputStream = new ZipInputStream(in, utf8);
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.toString().equals(entryName)) {
                    BufferedReader br;
                    br = new BufferedReader(new InputStreamReader(zf.getInputStream(zipEntry), utf8));
                    try {
                        String line;
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        manifestStr = sb.toString();
                    } catch (IOException e) {
                        log.error("Error in reading metadata");
                        throw new IOException("Error in reading metadata in " + metadataPath, e);
                    } finally {
                        br.close();
                    }
                }
            }
            zipInputStream.close();
            in.close();
            zf.close();
            if (!manifestStr.isEmpty()) {
                metadata = new MetadataSerializer().deserialize(manifestStr, GspMetadata.class);
            }

        } catch (IOException ioe) {
            log.error("构建元数据失败，元数据位置：" + metadataPath + "元数据id：" + metadataId, ioe);
        } finally {
            lock.unlock();
        }
        if (metadata == null) {
            throw new RuntimeException("Could not find metadata content!");
        }
        return metadata;
    }

    private GspMetadata getI18nMetadata(String metadataId, String language) {
        if (language == null) {
            language = RuntimeContext.getLanguage();
        }
        //从缓存中获取元数据，缓存中的元数据认为是国际化的元数据内容
        //缓存中不存在元数据，获取基础元数据内容，
        //根据基础元数据内容，获取国际化资源，
        //根据合并接口合并元数据，并返回内容，添加缓存。
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataId, language);
        GspMetadata metadataCache = (GspMetadata) MetadataCacheManager.getMetadataInfo(metadataKey);
        if (metadataCache != null) {
            return metadataCache;
        }
        GspMetadata originalData = getMetadataRTByID(metadataId);
        //获取多语资源，此处try为兼容各个未国际化的元数据
        try {
            List<I18nResource> resources = getI18nResourceRtManager().getI18nResource(originalData, language);
            MetadataI18nService service = I18nManagerHelper.getInstance().getI18nManager(originalData.getHeader().getType());
            if (service != null && resources != null && resources.size() > 0) {
                GspMetadata result = service.merge(originalData, resources);
                RtCacheHandler.updateMetadataCache(metadataKey, result);
                return result;
            }
        } catch (Exception e) {
            //TODO 表单强制获取资源项，获取不到时会报错，异常太多，暂时catch住
        }
        return originalData;
    }

    @Override
    public MetadataDto getMetadataDto(String id) {
        String language = RuntimeContext.getLanguage();
        return MetadataDtoConverter.asDto(getI18nMetadata(id, language));
    }

    @Override
    public GspMetadata getMetadata(String id) {
        String language = RuntimeContext.getLanguage();
        return getI18nMetadata(id, language);
    }

    @Override
    public List<GspMetadata> getMetadataListRecursivly(String path) {
        List<GspMetadata> result = new ArrayList<>();
        try {
            Map<String, MetadataPackage> packages = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(path));
            if (packages != null && packages.size() > 0) {
                for (Map.Entry<String, MetadataPackage> valuePair : packages.entrySet()) {
                    MetadataPackage metadataPackage = valuePair.getValue();
                    String metadataPackagePath = valuePair.getKey();
                    for (GspMetadata item : metadataPackage.getMetadataList()) {
                        GspMetadata metadata = getMetadataByIdAndMetadataPath(item.getHeader().getId(), metadataPackagePath + item.getRelativePath());
                        result.add(metadata);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("递归获取路径下元数据包中元数据列表报错，路径为" + path, e);
        }
        return result;
    }

    public List<GspMetadata> getExtendableMetadataListRecursivly(String path) {
        List<GspMetadata> result = new ArrayList<>();
        try {
            Map<String, MetadataPackage> packages = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(path));
            if (packages != null && packages.size() > 0) {
                for (Map.Entry<String, MetadataPackage> valuePair : packages.entrySet()) {
                    MetadataPackage metadataPackage = valuePair.getValue();
                    String metadataPackagePath = valuePair.getKey();
                    for (GspMetadata item : metadataPackage.getMetadataList()) {
                        if (item.getHeader().isExtendable()) {
                            GspMetadata metadata = getMetadataByIdAndMetadataPath(item.getHeader().getId(), metadataPackagePath + item.getRelativePath());
                            result.add(metadata);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("递归获取路径下元数据包中元数据列表报错，路径为" + path, e);
        }
        return result;
    }

    @Override
    public List<GspMetadata> getMetadataListFromPackage(String packagePath) {
        List<GspMetadata> result = new ArrayList<>();

        if (!fileService.isFileExist(packagePath)) {
            throw new RuntimeException("元数据包不存在，元数据包路径为" + packagePath);
        }
        try {
            MetadataPackage metadataPackage = RepositoryFactory.getInstance().getMetadataPackageRepository().getMetadataPackage(new File(packagePath));
            for (GspMetadata item : metadataPackage.getMetadataList()) {
                GspMetadata metadata = getMetadataByIdAndMetadataPath(item.getHeader().getId(), packagePath + item.getRelativePath());
                result.add(metadata);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public List<GspMetadata> getMetadataListInfoFromPackage(String packagePath) {
        List<GspMetadata> result = new ArrayList<>();

        if (!fileService.isFileExist(packagePath)) {
            throw new RuntimeException("元数据包不存在，元数据包路径为" + packagePath);
        }
        try {
            MetadataPackage metadataPackage = RepositoryFactory.getInstance().getMetadataPackageRepository().getMetadataPackage(new File(packagePath));
            if (Objects.isNull(metadataPackage)) {
                return null;
            }
            return metadataPackage.getMetadataList();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public Map<String, MetadataPackage> getMetadataPackagesRecursivly(String path) {
        Map<String, MetadataPackage> result;
        try {
            result = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(path));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("递归获取路径下元数据包中元数据列表报错，路径为" + path, e);
        }
        return result;
    }

    @Override
    public void loadAllMetadata() {
        String basePath = EnvironmentUtil.getBasePath();
        FileServiceImp fileService = new FileServiceImp();
        metadataAppPath = fileService.getCombinePath(basePath, "metadata/apps");
        metadataPlatformPath = fileService.getCombinePath(basePath, "metadata/platform");

        //元数据包信息，<元数据包绝对路径，元数据包信息>
        Map<String, MetadataPackage> packageDicInApps;
        Map<String, MetadataPackage> packageDic;
        List<GspMetadata> metadataInfoList = new ArrayList<>();
        try {
            packageDicInApps = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataAppPath));
            Map<String, MetadataPackage> packageDicInPlatform = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataPlatformPath));
            packageDic = Stream.concat(packageDicInApps.entrySet().stream(), packageDicInPlatform.entrySet().stream())
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue,
                    (value1, value2) -> value1));
        } catch (Exception e) {
            log.error("Error in reading metadata in metadata/apps or platform", e);
            throw new RuntimeException("Error in reading metadata in metadata/apps or platform", e);
        }
        if (packageDic.size() > 0) {
            for (Map.Entry<String, MetadataPackage> valuePair : packageDic.entrySet()) {
                String metadataPackagePath = valuePair.getKey();
                MetadataPackage metadataPackage = valuePair.getValue();
                if (metadataPackage != null) {
                    RtCacheHandler.updateMetadataPackageCache(metadataPackage.getHeader().getName(), metadataPackage);
                }
                for (GspMetadata item : metadataPackage.getMetadataList()) {
                    // + languageID;
                    String metadataKey = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), "");
                    MetadataCacheManager.addMetadataPathMapping(metadataKey, metadataPackagePath + item.getRelativePath());
                    metadataInfoList.add(item);
                }
                MetadataCacheManager.addAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY, metadataInfoList);
            }
        }
        Cache metadataCache = MetadataDistCacheManager.getMetadataCache();
        metadataCache.clear();
        Cache metadataRtCache = MetadataRtDistCache.getMetadataCache();
        metadataRtCache.clear();

        // 预加载序反列化器
        MetadataSerializerHelper.getInstance();
    }

    public void loadAllMetadataByPath(String path, String packagePath) {
        FileServiceImp fileService = new FileServiceImp();
        String metadataAppPath = fileService.getCombinePath(path, "metadata/apps");
        String metadataPlatformPath = fileService.getCombinePath(path, "metadata/platform");

        //元数据包信息，<元数据包绝对路径，元数据包信息>
        Map<String, MetadataPackage> packageDicInApps;
        Map<String, MetadataPackage> packageDic;
        List<GspMetadata> metadataInfoList = new ArrayList<>();
        try {
            packageDicInApps = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataAppPath));
            Map<String, MetadataPackage> packageDicInPlatform = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataPlatformPath));
            Map<String, MetadataPackage> packegeDicInDeployPath = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(packagePath));
            Map<String, MetadataPackage> serverPackageDic = Stream.concat(packageDicInApps.entrySet().stream(), packageDicInPlatform.entrySet().stream())
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue,
                    (value1, value2) -> value1));
            packageDic = Stream.concat(serverPackageDic.entrySet().stream(), packegeDicInDeployPath.entrySet().stream())
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue,
                    (value1, value2) -> value1));
        } catch (Exception e) {
            throw new RuntimeException("Error in reading metadata in metadata/apps or platform", e);
        }
        if (packageDic.size() > 0) {
            for (Map.Entry<String, MetadataPackage> valuePair : packageDic.entrySet()) {
                String metadataPackagePath = valuePair.getKey();
                MetadataPackage metadataPackage = valuePair.getValue();
                if (metadataPackage != null) {
                    RtCacheHandler.updateMetadataPackageCache(metadataPackage.getHeader().getName(), metadataPackage);
                }
                for (GspMetadata item : metadataPackage.getMetadataList()) {
                    // + languageID;
                    String metadataKey = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), "");
                    MetadataCacheManager.addMetadataPathMapping(metadataKey, metadataPackagePath + item.getRelativePath());
                    metadataInfoList.add(item);
                }
            }
            MetadataCacheManager.addAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY, metadataInfoList);
        }
        // 预加载序反列化器
        MetadataSerializerHelper.getInstance();
    }

    public List<Metadata4RefDto> getMetadataList(String metadataTypes) {
        List<Metadata4Ref> result = getMetadataRefListWithTypes(metadataTypes);
        return utils.buildMetadata4RefDto(result);
    }

    @Override
    public String getMetadataRefDtoList() {
        List<Metadata4Ref> metadataList = getMetadataRefList();
        return utils.serializeMetadata4RefDtos(utils.buildMetadata4RefDto(metadataList));
    }

    @Override
    public List<Metadata4Ref> getMetadataRefList() {
        List<Metadata4Ref> metadataList = new ArrayList<>();
        //首先从缓存获取
        List<MetadataPackage> packagesCache = (List<MetadataPackage>) MetadataCacheManager.getAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY);
        if (packagesCache != null && packagesCache.size() > 0) {
            for (MetadataPackage pack : packagesCache) {
                List<Metadata4Ref> metadata4Ref = getMetadata4Ref(pack, null);
                metadataList.addAll(metadata4Ref);
            }
            return metadataList;
        }
        List<MetadataPackage> metadataPackages = getMetadataPackages();
        for (MetadataPackage metadataPackage : metadataPackages) {
            List<Metadata4Ref> metadata4Ref = getMetadata4Ref(metadataPackage, null);
            metadataList.addAll(metadata4Ref);
        }
        MetadataCacheManager.addAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY, metadataPackages);
        return metadataList;
    }

    private List<MetadataPackage> getMetadataPackages() {

        serverBasePath = EnvironmentUtil.getBasePath();
        FileServiceImp fileService = new FileServiceImp();
        metadataAppPath = fileService.getCombinePath(serverBasePath, "metadata/apps");
        metadataPlatformPath = fileService.getCombinePath(serverBasePath, "metadata/platform");

        //元数据部署目录下遍历
        //List<String> paths = new ArrayList<>();
        //找到目录下的所有元数据包mdpkg
        //RepositoryFactory.getInstance().getMetadataPackageRepository().getMdpkgFilesPath(Utils.handlePath("metadata/apps"), paths);
        //RepositoryFactory.getInstance().getMetadataPackageRepository().getMdpkgFilesPath(Utils.handlePath("metadata/platform"), paths);

        //缓存的包列表
        List<MetadataPackage> metadataPackages = new ArrayList<>();
        //元数据包信息，<元数据包绝对路径，元数据包信息>
        Map<String, MetadataPackage> packageDicInApps;
        Map<String, MetadataPackage> packageDicInPlatform;

        try {
            packageDicInApps = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataAppPath));
            packageDicInPlatform = RepositoryFactory.getInstance().getMetadataPackageRepository().retrieveAllMdPkg(Utils.handlePath(metadataPlatformPath));
        } catch (Exception e) {
            log.error("Error in reading metadata in metadata/apps or platform", e);
            throw new RuntimeException("Error in reading metadata in metadata/apps or platform", e);
        }

        if (packageDicInApps.values().size() > 0) {
            metadataPackages.addAll(packageDicInApps.values());
        }
        if (packageDicInPlatform.values().size() > 0) {
            metadataPackages.addAll(packageDicInPlatform.values());
        }
        return metadataPackages;
    }

    @Override
    public String getMetadataDtoListByFilter(String filter) {
        MetadataRTFilter filterInfo = utils.deserializerMetadataRTFilter(filter);
        List<Metadata4Ref> metadataList = getMetadataListByFilter(filterInfo);
        return utils.serializeMetadata4RefDtos(utils.buildMetadata4RefDto(metadataList));
    }

    @Override
    public List<Metadata4Ref> getMetadataListByFilter(MetadataRTFilter filter) {

        List<Metadata4Ref> metadataList;
        // 获取所有元数据包
        metadataList = getMetadataRefList();
        // 根据AppCode进行过滤
        if (filter.getAppCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getServiceUnitInfo() == null || item.getServiceUnitInfo().getAppCode().equals(filter.getAppCode())).collect(Collectors.toList());
        }
        // 根据ServiceUnitCode进行过滤
        if (filter.getServiceUnitCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getServiceUnitInfo() == null || item.getServiceUnitInfo().getServiceUnitCode().equals(filter.getServiceUnitCode())).collect(Collectors.toList());
        }
        // 根据BizobjectID进行过滤
        if (filter.getBizobjectId() != null && filter.getBizobjectId().size() > 0) {
            for (String eachBizobjectId : filter.getBizobjectId()) {
                metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getBizObjectId().equals(eachBizobjectId)).collect(Collectors.toList());
            }
        }
        if (filter.getCode() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getCode() != null && item.getMetadata().getHeader().getCode().equals(filter.getCode())).collect(Collectors.toList());
        }
        if (filter.getNameSpace() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getNameSpace() != null && item.getMetadata().getHeader().getNameSpace().equals(filter.getNameSpace())).collect(Collectors.toList());
        }
        if (filter.getType() != null) {
            metadataList = metadataList.stream().filter(item -> item.getMetadata().getHeader().getType() != null && item.getMetadata().getHeader().getType().equals(filter.getType())).collect(Collectors.toList());
        }
        return metadataList;
    }

    /***
     * @author zhongchq
     * @param metadataTypes 想要获取的元数据类型
     * @return java.util.List<com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref>
     **/
    @Override
    public String getMetadataRefDtoListWithTypes(String metadataTypes) {
        List<Metadata4Ref> metadata4Refs = getMetadataRefListWithTypes(metadataTypes);
        return utils.serializeMetadata4RefDtos(utils.buildMetadata4RefDto(metadata4Refs));

    }

    @Override
    public List<Metadata4Ref> getMetadataRefListWithTypes(String metadataTypes) {
        List<String> typeList;
        if (metadataTypes == null || metadataTypes.isEmpty()) {
            throw new RuntimeException("传入参数不能为空");
        } else {
            String[] types = metadataTypes.split(",");
            typeList = new ArrayList<>(Arrays.asList(types));
        }
        List<Metadata4Ref> metadataList = new ArrayList<>();
        //首先从缓存获取
        List<MetadataPackage> packagesCache = (List<MetadataPackage>) MetadataCacheManager.getAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY);
        if (packagesCache != null && packagesCache.size() > 0) {
            for (MetadataPackage pack : packagesCache) {
                List<Metadata4Ref> metadata4Ref = getMetadata4Ref(pack, typeList);
                metadataList.addAll(metadata4Ref);
            }
            return metadataList;
        }

        List<MetadataPackage> metadataPackages = getMetadataPackages();
        for (MetadataPackage metadataPackage : metadataPackages) {
            List<Metadata4Ref> metadata4Ref = getMetadata4Ref(metadataPackage, typeList);
            metadataList.addAll(metadata4Ref);
        }

        MetadataCacheManager.addAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY, metadataPackages);
        return metadataList;
    }

    private List<Metadata4Ref> getMetadata4Ref(MetadataPackage packageInfo, List<String> metadataTypes) {
        List<Metadata4Ref> metadata4RefList = new ArrayList<>();
        if (metadataTypes != null && metadataTypes.size() > 0) {
            metadataTypes.forEach(type ->
                {
                    List<GspMetadata> result = packageInfo.getMetadataList().stream().filter(item -> item.getHeader().getType().toLowerCase().equals(type.toLowerCase())).collect(Collectors.toList());
                    if (result.size() > 0) {
                        result.forEach(metadata -> {
                            Metadata4Ref metadata4Ref = new Metadata4Ref();
                            metadata4Ref.setMetadata(metadata);
                            metadata4Ref.setServiceUnitInfo(packageInfo.getServiceUnitInfo());
                            metadata4Ref.setPackageHeader(packageInfo.getHeader());
                            metadata4RefList.add(metadata4Ref);
                        });
                    }
                }
            );
        } else {
            packageInfo.getMetadataList().forEach(metadata -> {
                Metadata4Ref metadata4Ref = new Metadata4Ref();
                metadata4Ref.setMetadata(metadata);
                metadata4Ref.setServiceUnitInfo(packageInfo.getServiceUnitInfo());
                metadata4Ref.setPackageHeader(packageInfo.getHeader());
                metadata4RefList.add(metadata4Ref);
            });
        }
        return metadata4RefList;
    }

    @Override
    public MetadataDto getMetadataDtoBySemanticID(String metadataNamespace, String metadataCode,
        String metadataTypeCode) {
        GspMetadata metadata = getMetadataBySemanticId(metadataNamespace, metadataCode, metadataTypeCode);
        return MetadataDtoConverter.asDto(metadata);
    }

    private GspMetadata getMetadataBySemanticId(String metadataNamespace, String metadataCode,
        String metadataTypeCode) {
        List<GspMetadata> allMetadataInfo = (List<GspMetadata>) MetadataCacheManager.getAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY);
        if (allMetadataInfo != null) {
            for (GspMetadata item : allMetadataInfo) {
                if (item.getHeader().getNameSpace().toLowerCase().equals(metadataNamespace.toLowerCase())
                    && item.getHeader().getCode().toLowerCase().equals(metadataCode.toLowerCase())
                    && item.getHeader().getType().toLowerCase().equals(metadataTypeCode.toLowerCase())) {
                    return getMetadataRTByID(item.getHeader().getId());
                }
            }
        }
        List<Metadata4RefDto> allMetadataList = getMetadataList(metadataTypeCode);
        if (allMetadataList != null) {
            for (Metadata4RefDto item : allMetadataList) {
                if (item.getMetadata().getNameSpace().toLowerCase().equals(metadataNamespace.toLowerCase())
                    && item.getMetadata().getCode().toLowerCase().equals(metadataCode.toLowerCase())) {
                    return getMetadataRTByID(item.getMetadata().getId());
                }
            }
        }
        return null;
    }

    @Override
    public ServiceUnitInfo getServiceUnitInfo(String metadataId) {
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataId, "");
        String metadataPackagePath = (String) MetadataCacheManager.getMetadataPathMapping(metadataKey);
        if (metadataPackagePath == null || metadataPackagePath.isEmpty()) {
            throw new IllegalArgumentException("Could not find metadata, metadataid is " + metadataId);
        }
        String entryName = metadataPackagePath.substring(metadataPackagePath.indexOf(MetadataUtils.getMetadataPackageExtension()) + MetadataUtils.getMetadataPackageExtension().length() + 1);
        metadataPackagePath = metadataPackagePath.substring(0, metadataPackagePath.indexOf(entryName) - 1);
        String metadataPackageName = new File(metadataPackagePath).getName();
        String metadataPackageNameWithoutSuffix = metadataPackageName.substring(0, metadataPackageName.indexOf(MetadataUtils.getMetadataPackageExtension()));
        MetadataPackage metadataPackage = (MetadataPackage) MetadataCacheManager.getMetadataPackageInfo(metadataPackageNameWithoutSuffix);
        return metadataPackage.getServiceUnitInfo();
    }

    @Override
    public String getMetadataString(MetadataCustomizationFilter metadataCustomizationFilter) {
        return getMetadataStrFromPackage(metadataCustomizationFilter.getMetadataId());
    }

    private String getMetadataStrFromPackage(String metadataID) {
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataID, "");
        String metadataPackagePath = (String) MetadataCacheManager.getMetadataPathMapping(metadataKey);
        if (metadataPackagePath == null || metadataPackagePath.isEmpty()) {
            return null;
        }
        String entryName = metadataPackagePath.substring(metadataPackagePath.indexOf(MetadataUtils.getMetadataPackageExtension()) + MetadataUtils.getMetadataPackageExtension().length() + 1);
        metadataPackagePath = metadataPackagePath.substring(0, metadataPackagePath.indexOf(entryName) - 1);
        String metadataStr = "";

        lock.lock();
        try {
            StringBuilder sb = new StringBuilder();
            File file = new File(metadataPackagePath);
            ZipFile zf = new ZipFile(file);
            InputStream in = new BufferedInputStream(new FileInputStream(metadataPackagePath));
            Charset utf8 = StandardCharsets.UTF_8;
            ZipInputStream zipInputStream = new ZipInputStream(in, utf8);
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.toString().equals(entryName)) {
                    BufferedReader br;
                    br = new BufferedReader(new InputStreamReader(zf.getInputStream(zipEntry), utf8));
                    try {
                        String line;
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        metadataStr = sb.toString();
                    } catch (IOException e) {
                        log.error("Error in reading metadata");
                        throw new IOException("Error in reading metadata in " + metadataPackagePath, e);
                    } finally {
                        br.close();
                    }
                }
            }
            zipInputStream.close();
            in.close();
            zf.close();
        } catch (IOException ioe) {
            log.error("构建元数据失败，元数据位置：" + metadataPackagePath + "元数据id：" + metadataID, ioe);
        } finally {
            lock.unlock();
        }
        if (StringUtils.isEmpty(metadataStr)) {
            throw new RuntimeException("Could not find metadata " + metadataID + " from " + metadataPackagePath);
        }
        return metadataStr;
    }
}
